package io.sundial.coordination.watching;

import io.sundial.coordination.CoordinatorException;
import io.sundial.core.Atomic;
import io.sundial.core.AtomicVTCommand;

import java.util.concurrent.atomic.AtomicReference;

/**
 * 原子性观察者句柄
 *
 * @author Payne 646742615@qq.com
 * 2018/12/28 16:37
 */
public abstract class StatedEventWatching extends Atomic implements EventWatching {
    private AtomicReference<State> state = new AtomicReference<>(State.PAUSED);

    @Override
    public State state() {
        return state.get();
    }

    @Override
    public void start() throws CoordinatorException {
        doWritingCommand(new AtomicVTCommand<CoordinatorException>() {
            @Override
            public void run() throws CoordinatorException {
                if (state.compareAndSet(State.PAUSED, State.WATCHING)) {
                    onStart();
                }
            }
        });
    }

    protected abstract void onStart() throws CoordinatorException;

    @Override
    public void pause() throws CoordinatorException {
        doWritingCommand(new AtomicVTCommand<CoordinatorException>() {
            @Override
            public void run() throws CoordinatorException {
                if (state.compareAndSet(State.WATCHING, State.PAUSED)) {
                    onPause();
                }
            }
        });
    }

    protected abstract void onPause() throws CoordinatorException;

    @Override
    public void close() throws CoordinatorException {
        doWritingCommand(new AtomicVTCommand<CoordinatorException>() {
            @Override
            public void run() throws CoordinatorException {
                if (state.compareAndSet(State.WATCHING, State.CLOSED) || state.compareAndSet(State.PAUSED, State.CLOSED)) {
                    onClose();
                }
            }
        });
    }

    protected abstract void onClose() throws CoordinatorException;
}
